/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cluelessserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author Dave
 */
public class Game {
    Board gameBoard = new Board();
    //Player[] characters = new Player[6];
    ArrayList<Player> playerList = new ArrayList();
    Card [] weaponCards = new Card[6];
    Card [] playerCards = new Card[6];
    Card [] roomCards = new Card[9];
    Card [] solution = new Card[3];
    ArrayList<Card> deck = new ArrayList<>();    
    String[] weaponName = {"Candlestick", "Knife", "Pipe", "Revolver", "Rope", "Wrench"};
    String[] playerName = {"Scarlet","Plum","Mustard","Peacock", "Green","White"};
    String[] roomName = {"Study", "Hall", "Lounge", "Library", "Billiard_Room", "Dining_Room", "Conservatory", "Ballroom", "Kitchen"};
    private Random randomGenerator;   
    boolean gameNotOver = true;
    int playersLost = 0;   
    String playerWon = "No one ";
    int numPlayers;    
    PrintWriter out;
    BufferedReader in;
    Player currentPlayer;
    
    /**
     * Finds the index of a player. Helper method used to return a player by its name.
     * @param name name of the player to locate
     * @return index in the playerName array
     */
    int getIndex(String name){
        int index = 0;
        for(int i = 0; i < 6;i++){
            if(playerName[i].equals(name)){
                index = i;
            }
        }
        return index;
    }
    
    /**
     * 
     * @param name
     * @return 
     */
    Player getPlayer(String name){
        Player p = null;
        int i = getIndex(name);
        p = playerList.get(i);
        return p;
    }
    
    
    Game(){}
    
    //create game with connections for real players and without for comp players
    Game(Connection[] connections) throws IOException{               
        //Prompt client for char. Looks like:
        //Prompt Scarlet (where Scarlet has already been selected)
        numPlayers = connections.length;
        String inMess;
        String charsClaimed = "";
        for(int i = 0; i < 6; i++){
            playerList.add(i, new Player(playerName[i], gameBoard));        
        }
        
        for(int i = 0; i < numPlayers; i++){            
            connections[i].out.println("Prompt" + charsClaimed);
            while((inMess = connections[i].in.readLine()) != null){
                System.out.println(inMess);
                int nameIndex = getIndex(inMess); 
                Player pl = playerList.get(nameIndex);               
                pl.addConnection(connections[i]);
                charsClaimed += " " + inMess;                
                break;
            }
        }        
        createDeck();                    
    }
    
    
    void broadcastGameStart() throws IOException{                
       System.out.println("inside broadcastGS");
        String playersAre = "The Players are:  ";
        for(int play = 0; play < 6; play++){        
            if(playerList.get(play).isHuman){  
                playersAre += playerList.get(play) + " ";  
            }           
        }            
        for(Player p : playerList){
            if(p.isHuman){
                p.sendMessage("Message" , playersAre);
                p.sendMessage("Message" , "You are player: " + p.name);            
                p.sendMessage("Hand", p.handToString());
                System.out.println("broadcastGS " + playersAre );
            }
        }
    }
    
    String generatePlayerUpdate(){
        String update = "";
        for (int i = 0; i < 6; i++){
           update += playerList.get(i).toString() + " " + playerList.get(i).location.toString() + " ";
        }        
        return update;
    }
    
    void gameStart() throws IOException{        
        currentPlayer = playerList.get(5);
        currentPlayer = getNextPlayer();        
        String inMessage = null;        
        broadcastGameStart();         
        
        while (gameNotOver){            
            out = currentPlayer.conn.out;
            in = currentPlayer.conn.in;            
            //sends message to everyone about who's turn it is
            broadcastTurnStart(); 
            //Turn loop
            boolean turnNotOver = true;
            
            while(turnNotOver){                
                System.out.println("Send moves to " + currentPlayer.name);
                sendMoves(currentPlayer);
                while((inMessage = in.readLine()) != null){                    
                    System.out.println("inMessage "+inMessage);
                    if(inMessage.startsWith("Move")){
                        processMove(currentPlayer,inMessage.split(" "));
                        break;
                    } else if(inMessage.startsWith("Suggest")){
                        broadcastSuggest(inMessage.split(" "));
                        break;
                    } else if(inMessage.startsWith("Accuse")){
                        turnNotOver = false;
                        broadcastAccuse(inMessage.split(" "));
                        break;
                    } else if(inMessage.startsWith("EndTurn")){
                        turnNotOver = false;
                        currentPlayer.hasMoved = false;
                        currentPlayer.hasMadeSugg = false;                       
                        break;
                    } else {
                        System.out.println("InMessagefallthrough " + inMessage);
                    }
                }
            }
            //Turn over
            if(gameNotOver){
            currentPlayer = getNextPlayer();
            System.out.println("Turn Over");
            }
        }
        //Game Over
        System.out.println("Game Over");
        
        broadcastGameOver(playerWon);
    }
    
    void processMove(Player p, String[] move) throws IOException{        
        
        switch (move[1]){
            case "North":   p.setLocation(p.location.roomNorth);                        
                            break;
            case "South":   p.setLocation(p.location.roomSouth);
                             break;
            case "West":    p.setLocation(p.location.roomWest);
                            break;
            case "East":    p.setLocation(p.location.roomEast);
                            break;
            case "Secret":  p.setLocation(p.location.roomSecret);
                            break;         
        }
        p.hasMoved = true;
        //sends a text message informing of the move then sends position update to all clients
        broadcastMessage(p.toString() + " has moved to the " + p.location.toString());
        //broadcastMessage(generatePlayerUpdate());
        broadcastUpdate();
    }
    
    String getMoves(Player p){
        String moves = "";        
        moves += "Turn You Moves " + p.location.getMovesToString();
        return moves;        
    }
    
    void createDeck(){                
        currentPlayer = playerList.get(5);
        currentPlayer = getNextPlayer();
        
        for (int i = 0; i < 6; i++){  
            weaponCards[i] = new WeaponCard(weaponName[i]);
            Player pl = getPlayer(playerName[i]);
            playerCards[i] = new PlayerCard(playerName[i], pl);       
        }
        for (int i = 0; i < 9; i++){            
            BoardSpace rm = gameBoard.getRoom(roomName[i]);
            roomCards[i] = new RoomCard(roomName[i], rm);
        }
        //cards have been initialized
        //now we need to create solution and deal the rest to players
        int ranPlayer = (int)(Math.random() * 6);
        int ranWeap = (int)(Math.random() * 6);
        int ranRoom = (int)(Math.random() * 9);        
        solution[0] = playerCards[ranPlayer];
        playerCards[ranPlayer].isInSolution = true;
        solution[1] = weaponCards[ranWeap];
        weaponCards[ranWeap].isInSolution = true;
        solution[2] = roomCards[ranRoom];
        roomCards[ranRoom].isInSolution = true;
        
        for (int i = 0;i < 6; i++){
            if (!weaponCards[i].isInSolution){
                 deck.add(weaponCards[i]);
            }
            if (!playerCards[i].isInSolution){
                deck.add(playerCards[i]);
            }
        }
        for (int i = 0;i < 9; i++){
            if (!roomCards[i].isInSolution){
                 deck.add(roomCards[i]);
            }            
        }
//all cards are in deck except solution now       
        randomGenerator = new Random();
        while (deck.size() > 0){            
            int index = randomGenerator.nextInt(deck.size());
            Card card = deck.get(index);
            currentPlayer.hand.add(card);
            deck.remove(index);
            currentPlayer = getNextPlayer();
        }
    }

    private void broadcastMessage(String message) throws IOException {        
        for(Player p : playerList){            
            if(p.isHuman){
                p.sendMessage("Message", message);
            }
        }        
    }
    
    private void broadcastSuggest(String [] sugg) throws IOException {
        //0 Player
        //1 weapon
        //2 room
        boolean isNotRefPlayer = false;
        boolean isNotRefWeap = false;
        boolean isNotRefRoom = false;
        currentPlayer.hasMadeSugg = true;
        //move suggested player to room in suggestion
        Player accused = getPlayer(sugg[1]);        
        accused.setLocation(gameBoard.getRoom(sugg[3]));
        System.out.println(accused + " sent to "+ accused.location);
        broadcastMessage(accused + " sent to "+ accused.location);
        broadcastUpdate();
        if (sugg[1].equals(solution[0].toString()) || currentPlayer.hasCard(sugg[1])){
            isNotRefPlayer = true;
        }
        if (sugg[2].equals(solution[1].toString()) || currentPlayer.hasCard(sugg[2])){
            isNotRefWeap = true;
        }
        if (sugg[3].equals(solution[2].toString()) || currentPlayer.hasCard(sugg[3])){
            isNotRefRoom = true;
        }
        if((isNotRefPlayer && isNotRefWeap && isNotRefRoom)){
            broadcastMessage(currentPlayer.toString() + " Made a Suggestion that noone refuted!");
            broadcastMessage("Suggestion: " + sugg[1].toString() + ", with the " + sugg[2].toString() + ", in the " + sugg[3].toString());
        } else {            
            boolean refPl = false;
            boolean refWp = false;
            boolean refRm = false;
            
            Player playerToRef = null;
            while(!(refPl || refWp || refRm)){            
                playerToRef = findNextPlayer();       
                
                if (playerToRef.hasCard(sugg[1])){
                    refPl = true;                    
                   
                } 
                if (playerToRef.hasCard(sugg[2])){
                    refWp = true;                   
                    
                } 
                if (playerToRef.hasCard(sugg[3])){
                    refRm = true; 
                }
            }
            in = playerToRef.conn.in;
            broadcastMessage(currentPlayer.toString() + " Suggestion: " + sugg[1] + ", " + sugg[2] + ", " + sugg[3]);
            sendUpdate(playerToRef, "Refute", currentPlayer.toString() + " " + sugg[1] + " " + sugg[2] + " " + sugg[3] + " " + refPl + " " + refWp + " " + refRm);
            String inRefute = null;
            String refutedCard = "";
            
            while((inRefute = in.readLine()) != null){                    
                    System.out.println("inrefute " + inRefute);
                    break;
            }
            if(inRefute.equals("p")){
                refutedCard = sugg[1];
            } else if (inRefute.equals("w")){
                refutedCard = sugg[2];
            } else if (inRefute.equals("r")){
                refutedCard = sugg[3];
            }
            in = currentPlayer.conn.in;
            sendUpdate(currentPlayer, "Message", playerToRef.toString() + " has the " + refutedCard + " card !");
            broadcastMessage(playerToRef.toString() + " refutes the suggestion!");
           
        }
    }
private void broadcastAccuse(String [] acc) throws IOException {
        boolean isNotRefPlayer = false;
        boolean isNotRefWeap = false;
        boolean isNotRefRoom = false;         
    
        broadcastMessage(currentPlayer.toString() + " made an Accusation!");
        broadcastMessage("Accusation: " + acc[1] + ", with the " + acc[2] + ", in the " + acc[3]);        
        
        if (acc[1].equals(solution[0].toString())){
            isNotRefPlayer = true;
        }
        if (acc[2].equals(solution[1].toString())){
            isNotRefWeap = true;
        }
        if (acc[3].equals(solution[2].toString())){
            isNotRefRoom = true;
        }
        
        if(isNotRefPlayer && isNotRefWeap && isNotRefRoom){            
            broadcastMessage(currentPlayer.toString() + " found the solution!");
            gameOver(currentPlayer);
        } else {
            currentPlayer.hasLost = true;
            playersLost++;            
            broadcastMessage(currentPlayer + " made a false accusation!");
            broadcastMessage(currentPlayer + " lost the game!");
            if(playersLost == numPlayers){
                System.out.println("everyone lost");
                gameOver();                
            }  
            
        }  
    }

    private void sendUpdate(Player client, String type, String text) throws IOException {
        client.sendMessage(type, text);
    }
    
    Player getNextPlayer(){
        //gets the next player who is still playing
        Player p = null;
        int i = getIndex(currentPlayer.name);
        while(p == null){
            if(i == 5){
                i = 0;
            } else {
                i++;
            }
            if((playerList.get(i).isHuman) && !playerList.get(i).hasLost){
                p = playerList.get(i);
            }
        }
        return p;
    }
    
    Player findNextPlayer(){
        //gets the next human player. Used for refuting with people who have lost
        Player p = null;
        int i = getIndex(currentPlayer.name);
        while(p == null){
            if(i == 5){
                i = 0;
            } else {
                i++;
            }
            if((playerList.get(i).isHuman)){
                p = playerList.get(i);
            }
        }
        return p;
    
    }
    

    private void gameOver(Player player) throws IOException {
        gameNotOver = false;
        playerWon = player.toString();
    }
    
    private void gameOver() throws IOException {
        gameNotOver = false;
        playerWon = "No one";
    }

    private void broadcastTurnStart() throws IOException {        
        for(Player p: playerList){           
            String pTurn = "It is ";
            if(p.equals(currentPlayer)){
                    pTurn += "your";
            } else {
                pTurn += currentPlayer.name + "'s";
            }
            pTurn += " turn";
            if(p.isHuman){
                p.sendMessage("Message", pTurn);   
            }
        }
    }

    private void sendMoves(Player p) throws IOException {       
        Boolean firstMove = true;
        String moves = "";
        if(!p.hasMoved){
            moves += p.location.getMovesToString();            
            firstMove = false;
        }
        if((!p.hasMadeSugg) && p.location.isRoom && p.hasMoved){             
            if(!firstMove){
                moves += " ";
            }
            moves += "Suggest" + p.location.toString();
            firstMove = false;
        }
        if(!firstMove){
                moves += " ";
            }
        moves += "Accuse EndTurn";
        System.out.println("Sending Moves: " + moves + " player "+ p.name);
        p.sendMessage("Moves", moves);
    }

    private void broadcastGameOver(String playerWon) throws IOException {
        broadcastMessage("Game Over: " + playerWon + " won!");        
        for(Player p: playerList){
            if(p.isHuman){
                p.sendMessage("GameOver", playerWon);   
            }
        }
    }

    private void broadcastUpdate() throws IOException {
       for(Player p : playerList){            
            if(p.isHuman){
                p.sendMessage("Update",generatePlayerUpdate());
            }
        }    
    }
}